home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 039a / dflat8.zip / EDITBOX.C < prev    next >
Text File  |  1991-09-30  |  27KB  |  1,164 lines

  1. /* ------------- editbox.c ------------ */
  2.  
  3. #include "dflat.h"
  4.  
  5. #define EDITBUFFERLENGTH  1024
  6. #define ENTRYBUFFERLENGTH 256
  7. #define GROWLENGTH        64
  8.  
  9. #define EditBufLen(wnd) (isMultiLine(wnd) ? EDITBUFFERLENGTH : ENTRYBUFFERLENGTH)
  10.  
  11. static void SaveDeletedText(WINDOW, char *, int);
  12. static void Forward(WINDOW);
  13. static void Backward(WINDOW);
  14. static void End(WINDOW);
  15. static void Home(WINDOW);
  16. static void Downward(WINDOW);
  17. static void Upward(WINDOW);
  18. static void StickEnd(WINDOW);
  19. static void UpLine(WINDOW);
  20. static void DownLine(WINDOW);
  21. static void NextWord(WINDOW);
  22. static void PrevWord(WINDOW);
  23. static void ResetEditBox(WINDOW);
  24. static void AddTextPointers(WINDOW, int, int);
  25. #define SetLinePointer(wnd, ln)    (wnd->CurrLine = ln)
  26.  
  27. static int KeyBoardMarking, ButtonDown;
  28. int TextMarking;
  29. static int bx, by;
  30. static int py = -1;
  31.  
  32. char *Clipboard;
  33. int ClipboardLength;
  34.  
  35. static int CreateWindowMsg(WINDOW wnd)
  36. {
  37.     int rtn = BaseWndProc(EDITBOX, wnd, CREATE_WINDOW, 0, 0);
  38.     wnd->text = calloc(1, EditBufLen(wnd)+2);
  39.     wnd->textlen = EditBufLen(wnd);
  40.     wnd->InsertMode = TRUE;
  41.     ResetEditBox(wnd);
  42.     return rtn;
  43. }
  44.  
  45. static int AddTextMsg(WINDOW wnd, PARAM p1, PARAM p2)
  46. {
  47.     int rtn = BaseWndProc(EDITBOX, wnd, ADDTEXT, p1, p2);
  48.     if (!isMultiLine(wnd))    {
  49.         wnd->CurrLine = 0;
  50.         wnd->CurrCol = strlen((char *)p1);
  51.         if (wnd->CurrCol >= ClientWidth(wnd))    {
  52.             wnd->wleft = wnd->CurrCol - ClientWidth(wnd);
  53.             wnd->CurrCol -= wnd->wleft;
  54.         }
  55.         wnd->BlkEndCol = wnd->CurrCol;
  56.         SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  57.     }
  58.     BuildTextPointers(wnd);
  59.     return rtn;
  60. }
  61.  
  62. static int KeyboardCursorMsg(WINDOW wnd, PARAM p1, PARAM p2)
  63. {
  64.     int rtn;
  65.     wnd->CurrCol = (int)p1 + wnd->wleft;
  66.     wnd->WndRow = (int)p2;
  67.     wnd->CurrLine = (int)p2 + wnd->wtop;
  68.     rtn = BaseWndProc(EDITBOX, wnd, KEYBOARD_CURSOR, p1, p2);
  69.     if (wnd == inFocus)    {
  70.         if (!CharInView(wnd, (int)p1, (int)p2))
  71.             SendMessage(NULL, HIDE_CURSOR, 0, 0);
  72.         else 
  73.             SendMessage(NULL, SHOW_CURSOR, wnd->InsertMode, 0);
  74.     }
  75.     return rtn;
  76. }
  77.  
  78. static int SetFocusMsg(WINDOW wnd, PARAM p1)
  79. {
  80.     int rtn = BaseWndProc(EDITBOX, wnd, SETFOCUS, p1, 0);
  81.     if (p1)    {
  82.         SendMessage(NULL, SHOW_CURSOR, wnd->InsertMode, 0);
  83.         SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  84.     }
  85.     else
  86.         SendMessage(NULL, HIDE_CURSOR, 0, 0);
  87.     return rtn;
  88. }
  89.  
  90. static void ShiftChangedMsg(WINDOW wnd, PARAM p1)
  91. {
  92.     if (!((int)p1 & (LEFTSHIFT | RIGHTSHIFT)) && KeyBoardMarking)    {
  93.         SendMessage(wnd, BUTTON_RELEASED, 0, 0);
  94.         KeyBoardMarking = FALSE;
  95.     }
  96. }
  97.  
  98. static void GetTextMsg(WINDOW wnd, PARAM p1, PARAM p2)
  99. {
  100.     char *cp1 = (char *)p1;
  101.     char *cp2 = wnd->text;
  102.     while (p2-- && *cp2 && *cp2 != '\n')
  103.         *cp1++ = *cp2++;
  104.     *cp1 = '\0';
  105. }
  106.  
  107. static void LeftButtonMsg(WINDOW wnd, PARAM p1, PARAM p2)
  108. {
  109.     int mx = (int) p1 - GetClientLeft(wnd);
  110.     int my = (int) p2 - GetClientTop(wnd);
  111.     char *lp;
  112.     int len;
  113.  
  114.     if (isMultiLine(wnd))    {
  115.  
  116.         if (TextBlockMarked(wnd))    {
  117.             ClearTextBlock(wnd);
  118.             SendMessage(wnd, PAINT, 0, 0);
  119.         }
  120.  
  121.         if (wnd->wlines)    {
  122.             if (my > wnd->wlines-1)
  123.                 return;
  124.             lp = TextLine(wnd, my+wnd->wtop);
  125.             len = (int) (strchr(lp, '\n') - lp);
  126.             mx = min(mx, len);
  127.             if (mx < wnd->wleft)    {
  128.                 mx = 0;
  129.                 SendMessage(wnd, KEYBOARD, HOME, 0);
  130.             }
  131.             ButtonDown = TRUE;
  132.             bx = mx;
  133.             by = my;
  134.         }
  135.         else
  136.             mx = my = 0;
  137.  
  138.         wnd->WndRow = my;
  139.         SetLinePointer(wnd, my+wnd->wtop);
  140.     }
  141.     if (isMultiLine(wnd) ||
  142.         (!TextBlockMarked(wnd)
  143.             && mx+wnd->wleft < strlen(wnd->text)))
  144.         wnd->CurrCol = mx+wnd->wleft;
  145.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  146. }
  147.  
  148. static int MouseMovedMsg(WINDOW wnd, PARAM p1, PARAM p2)
  149. {
  150.     int mx = (int) p1 - GetClientLeft(wnd);
  151.     int my = (int) p2 - GetClientTop(wnd);
  152.     if (my > wnd->wlines-1)
  153.         return FALSE;
  154.     if (ButtonDown)    {
  155.         SetAnchor(wnd, bx+wnd->wleft, by+wnd->wtop);
  156.         TextMarking = TRUE;
  157.         SendMessage(wnd, CAPTURE_MOUSE, TRUE, 0);
  158.         ButtonDown = FALSE;
  159.     }
  160.     if (TextMarking && !(WindowMoving || WindowSizing))    {
  161.         int ptop;
  162.         int pbot;
  163.         char *lp;
  164.         int len;
  165.         int y;
  166.         int bbl, bel;
  167.         RECT rc = ClientRect(wnd);
  168.  
  169.         if (!InsideRect(p1, p2, rc))      {
  170.             int hs = -1, sc = -1;
  171.             if (p1 < GetClientLeft(wnd))    {
  172.                 hs = FALSE;
  173.                 p1 = GetClientLeft(wnd);
  174.             }
  175.             if (p1 > GetClientRight(wnd))    {
  176.                 hs = TRUE;
  177.                 p1 = GetClientRight(wnd);
  178.             }
  179.             if (p2 < GetClientTop(wnd))    {
  180.                 sc = FALSE;
  181.                 p2 = GetClientTop(wnd);
  182.             }
  183.             if (p2 > GetClientBottom(wnd))    {
  184.                 sc = TRUE;
  185.                 p2 = GetClientBottom(wnd);
  186.             }
  187.             SendMessage(NULL, MOUSE_CURSOR, p1, p2);
  188.             if (sc != -1)
  189.                 SendMessage(wnd, SCROLL, sc, 0);
  190.             if (hs != -1)
  191.                 SendMessage(wnd, HORIZSCROLL, hs, 0);
  192.             mx = (int) p1 - GetClientLeft(wnd);
  193.             my = (int) p2 - GetClientTop(wnd);
  194.         }
  195.  
  196.         ptop = min(wnd->BlkBegLine, wnd->BlkEndLine);
  197.         pbot = max(wnd->BlkBegLine, wnd->BlkEndLine);
  198.  
  199.         lp = TextLine(wnd, wnd->wtop+my);
  200.         len = (int) (strchr(lp, '\n') - lp);
  201.         mx = min(mx, len-wnd->wleft);
  202.  
  203.         wnd->BlkEndCol = mx+wnd->wleft;
  204.         wnd->BlkEndLine = my+wnd->wtop;
  205.  
  206.         bbl = min(wnd->BlkBegLine, wnd->BlkEndLine);
  207.         bel = max(wnd->BlkBegLine, wnd->BlkEndLine);
  208.  
  209.         while (ptop < bbl)    {
  210.             WriteTextLine(wnd, NULL, ptop, FALSE);
  211.             ptop++;
  212.         }
  213.         for (y = bbl; y <= bel; y++)
  214.             WriteTextLine(wnd, NULL, y, FALSE);
  215.         while (pbot > bel)    {
  216.             WriteTextLine(wnd, NULL, pbot, FALSE);
  217.             --pbot;
  218.         }
  219.         return TRUE;
  220.     }
  221.     return FALSE;
  222. }
  223.  
  224. static int ButtonReleasedMsg(WINDOW wnd)
  225. {
  226.     if (isMultiLine(wnd))    {
  227.         ButtonDown = FALSE;
  228.         if (TextMarking && !(WindowMoving || WindowSizing))    {
  229.             PostMessage(wnd, RELEASE_MOUSE, 0, 0);
  230.             TextMarking = FALSE;
  231.             if (wnd->BlkBegLine > wnd->BlkEndLine)    {
  232.                 swap(wnd->BlkBegLine, wnd->BlkEndLine);
  233.                 swap(wnd->BlkBegCol, wnd->BlkEndCol);
  234.             }
  235.             if (wnd->BlkBegLine == wnd->BlkEndLine &&
  236.                     wnd->BlkBegCol > wnd->BlkEndCol)
  237.                 swap(wnd->BlkBegCol, wnd->BlkEndCol);
  238.             return TRUE;
  239.         }
  240.         else
  241.             py = -1;
  242.     }
  243.     return FALSE;
  244. }
  245.  
  246. static int ScrollMsg(WINDOW wnd, PARAM p1, PARAM p2)
  247. {
  248.     int rtn = FALSE;
  249.     if (isMultiLine(wnd))    {
  250.         if ((rtn = BaseWndProc(EDITBOX, wnd, SCROLL, p1, 0)) != FALSE)    {
  251.             if (p1)    {
  252.                 /* -------- scrolling up --------- */
  253.                 if (wnd->WndRow == 0)    {
  254.                     DownLine(wnd);
  255.                     StickEnd(wnd);
  256.                 }
  257.                 else
  258.                     --wnd->WndRow;
  259.             }
  260.             else    {
  261.                 /* -------- scrolling down --------- */
  262.                 if (wnd->WndRow == ClientHeight(wnd)-1)    {
  263.                     UpLine(wnd);
  264.                     StickEnd(wnd);
  265.                 }
  266.                 else
  267.                     wnd->WndRow++;
  268.             }
  269.             if (!(int)p2)
  270.                 SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  271.         }
  272.     }
  273.     return rtn;
  274. }
  275.  
  276. static int HorizScrollMsg(WINDOW wnd, PARAM p1)
  277. {
  278.     int rtn = FALSE;
  279.     char *currchar = CurrChar;
  280.     if (!(p1 && wnd->CurrCol == wnd->wleft && *currchar == '\n'))    {
  281.         if ((rtn = BaseWndProc(EDITBOX, wnd, HORIZSCROLL, p1, 0)) != FALSE)    {
  282.             if (wnd->CurrCol < wnd->wleft)
  283.                 wnd->CurrCol++;
  284.             else if (WndCol == ClientWidth(wnd))
  285.                 --wnd->CurrCol;
  286.             SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  287.         }
  288.     }
  289.     return rtn;
  290. }
  291.  
  292. int SizeMsg(WINDOW wnd, PARAM p1, PARAM p2)
  293. {
  294.     int rtn = BaseWndProc(EDITBOX, wnd, SIZE, p1, p2);
  295.     if (WndCol > ClientWidth(wnd)-1)
  296.         wnd->CurrCol = ClientWidth(wnd)-1 + wnd->wleft;
  297.     if (wnd->WndRow > ClientHeight(wnd)-1)    {
  298.         wnd->WndRow = ClientHeight(wnd)-1;
  299.         SetLinePointer(wnd, wnd->WndRow+wnd->wtop);
  300.     }
  301.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  302.     return rtn;
  303. }
  304.  
  305. static int ScrollPageMsg(WINDOW wnd, PARAM p1)
  306. {
  307.     int rtn = FALSE;
  308.     if (isMultiLine(wnd))    {
  309.         rtn = BaseWndProc(EDITBOX, wnd, SCROLLPAGE, p1, 0);
  310.         SetLinePointer(wnd, wnd->wtop+wnd->WndRow);
  311.         StickEnd(wnd);
  312.         SendMessage(wnd, KEYBOARD_CURSOR,WndCol, wnd->WndRow);
  313.     }
  314.     return rtn;
  315. }
  316.  
  317. static int HorizPageMsg(WINDOW wnd, PARAM p1)
  318. {
  319.     int rtn = BaseWndProc(EDITBOX, wnd, HORIZPAGE, p1, 0);
  320.     if ((int) p1 == FALSE)    {
  321.         if (wnd->CurrCol > wnd->wleft+ClientWidth(wnd)-1)
  322.             wnd->CurrCol = wnd->wleft+ClientWidth(wnd)-1;
  323.     }
  324.     else if (wnd->CurrCol < wnd->wleft)
  325.         wnd->CurrCol = wnd->wleft;
  326.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  327.     return rtn;
  328. }
  329.  
  330. static void DoMultiLines(WINDOW wnd, int c, PARAM p2)
  331. {
  332.     if (isMultiLine(wnd))    {
  333.         if ((int)p2 & (LEFTSHIFT | RIGHTSHIFT))    {
  334.             int kx, ky;
  335.             SendMessage(NULL, CURRENT_KEYBOARD_CURSOR,
  336.                 (PARAM) &kx, (PARAM) &ky);
  337.             kx -= GetClientLeft(wnd);
  338.             ky -= GetClientTop(wnd);
  339.             switch (c)    {
  340.                 case HOME:
  341.                 case END:
  342.                 case PGUP:
  343.                 case PGDN:
  344.                 case CTRL_PGUP:
  345.                 case CTRL_PGDN:
  346.                 case UP:
  347.                 case DN:
  348.                 case FWD:
  349.                 case BS:
  350.                 case CTRL_FWD:
  351.                 case CTRL_BS:
  352.                     if (!KeyBoardMarking)    {
  353.                         if (TextBlockMarked(wnd))    {
  354.                             ClearTextBlock(wnd);
  355.                             SendMessage(wnd, PAINT, 0, 0);
  356.                         }
  357.                         KeyBoardMarking = TextMarking = TRUE;
  358.                         SetAnchor(wnd, kx+wnd->wleft, ky+wnd->wtop);
  359.                     }
  360.                     break;
  361.                 default:
  362.                     break;
  363.             }
  364.         }
  365.         else if (((c != DEL && c != RUBOUT) ||
  366.                 !isMultiLine(wnd)) && TextBlockMarked(wnd))    {
  367.             ClearTextBlock(wnd);
  368.             SendMessage(wnd, PAINT, 0, 0);
  369.         }
  370.     }
  371. }
  372.  
  373. static void DoScrolling(WINDOW wnd, int c, PARAM p2)
  374. {
  375.     switch (c)    {
  376.         case PGUP:
  377.         case PGDN:
  378.             if (isMultiLine(wnd))
  379.                 BaseWndProc(EDITBOX, wnd, KEYBOARD, c, p2);
  380.             break;
  381.         case CTRL_PGUP:
  382.         case CTRL_PGDN:
  383.             BaseWndProc(EDITBOX, wnd, KEYBOARD, c, p2);
  384.             break;
  385.         case HOME:
  386.             Home(wnd);
  387.             break;
  388.         case END:
  389.             End(wnd);
  390.             break;
  391.         case CTRL_FWD:
  392.             NextWord(wnd);
  393.             break;
  394.         case CTRL_BS:
  395.             PrevWord(wnd);
  396.             break;
  397.         case CTRL_HOME:
  398.             if (isMultiLine(wnd))    {
  399.                 SendMessage(wnd, SCROLLDOC, TRUE, 0);
  400.                 wnd->CurrLine = 0;
  401.                 wnd->WndRow = 0;
  402.             }
  403.             Home(wnd);
  404.             break;
  405.         case CTRL_END:
  406.             if (isMultiLine(wnd) && wnd->wlines > 0)    {
  407.                 SendMessage(wnd, SCROLLDOC, FALSE, 0);
  408.                 SetLinePointer(wnd, wnd->wlines-1);
  409.                 wnd->WndRow = min(ClientHeight(wnd)-1, wnd->wlines-1);
  410.                 Home(wnd);
  411.             }
  412.             End(wnd);
  413.             break;
  414.         case UP:
  415.             if (!isMultiLine(wnd))
  416.                 break;
  417.             Upward(wnd);
  418.             break;
  419.         case DN:
  420.             if (!isMultiLine(wnd))
  421.                 break;
  422.             Downward(wnd);
  423.             break;
  424.         case FWD:
  425.             Forward(wnd);
  426.             break;
  427.         case BS:
  428.             Backward(wnd);
  429.             break;
  430.         default:
  431.             break;
  432.     }
  433. }
  434.  
  435. static int MovementKey(WINDOW wnd, int c)
  436. {
  437.     if (!isMultiLine(wnd) && TextBlockMarked(wnd))    {
  438.         ClearTextBlock(wnd);
  439.         SendMessage(wnd, PAINT, 0, 0);
  440.     }
  441.     if (c != RUBOUT || (wnd->CurrLine == 0 && wnd->CurrCol == 0))
  442.         return TRUE;
  443.     Backward(wnd);
  444.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  445.     return FALSE;
  446. }
  447.  
  448. static int DelKey(WINDOW wnd)
  449. {
  450.     char *currchar = CurrChar;
  451.     int repaint = *currchar == '\n';
  452.     if (TextBlockMarked(wnd))    {
  453.         SendMessage(wnd, COMMAND, ID_DELETETEXT, 0);
  454.         SendMessage(wnd, PAINT, 0, 0);
  455.         return TRUE;
  456.     }
  457.     if (*(currchar+1) == '\0')
  458.         return TRUE;
  459.     strcpy(currchar, currchar+1);
  460.     if (repaint)    {
  461.         BuildTextPointers(wnd);
  462.         SendMessage(wnd, PAINT, 0, 0);
  463.     }
  464.     else    {
  465.         AddTextPointers(wnd, wnd->CurrLine+1, -1);
  466.         WriteTextLine(wnd, NULL, wnd->WndRow+wnd->wtop, FALSE);
  467.     }
  468.     wnd->TextChanged = TRUE;
  469.     return FALSE;
  470. }
  471.  
  472. static int TabKey(WINDOW wnd, PARAM p2)
  473. {
  474.     if (isMultiLine(wnd))    {
  475.         int insmd = wnd->InsertMode;
  476.         do  {
  477.             char *cc = CurrChar+1;
  478.             if (!insmd && *cc == '\0')
  479.                 break;
  480.             SendMessage(wnd, KEYBOARD,
  481.                 insmd ? ' ' : FWD, 0);
  482.         } while (wnd->CurrCol % cfg.Tabs);
  483.         return TRUE;
  484.     }
  485.     PostMessage(GetParent(wnd), KEYBOARD, '\t', p2);
  486.     return FALSE;
  487. }
  488.  
  489. static void KeyTyped(WINDOW wnd, int c)
  490. {
  491.     char *currchar = CurrChar;
  492.     if ((c != '\n' && c < ' ') || (c & 0x1000))
  493.         /* ---- not recognized by editor --- */
  494.         return;
  495.     if (!isMultiLine(wnd) && TextBlockMarked(wnd))    {
  496.         ResetEditBox(wnd);
  497.         ClearTextBlock(wnd);
  498.         currchar = CurrChar;
  499.     }
  500.     if (*currchar == '\0')    {
  501.         /* ---- typing at end of text ---- */
  502.         *currchar = '\n';
  503.         *(currchar+1) = '\0';
  504.         BuildTextPointers(wnd);
  505.     }
  506.     /* --- displayable char or newline --- */
  507.     if (c == '\n' || wnd->InsertMode ||    *currchar == '\n')    {
  508.         if (wnd->text[wnd->textlen-1] != '\0')    {
  509.             wnd->textlen += GROWLENGTH;
  510.             wnd->text = realloc(wnd->text, wnd->textlen+2);
  511.             wnd->text[wnd->textlen-1] = '\0';
  512.             currchar = CurrChar;
  513.         }
  514.         /* ------ insert mode ------ */
  515.         memmove(currchar+1, currchar, strlen(currchar)+1);
  516.         AddTextPointers(wnd, wnd->CurrLine+1, 1);
  517.         if (isMultiLine(wnd) && wnd->wlines > 1)
  518.             wnd->textwidth = max(wnd->textwidth,
  519.                 (int) (TextLine(wnd, wnd->CurrLine+1)-
  520.                 TextLine(wnd, wnd->CurrLine)));
  521.         else
  522.             wnd->textwidth = max(wnd->textwidth,
  523.                 strlen(wnd->text));
  524.         WriteTextLine(wnd, NULL,
  525.             wnd->wtop+wnd->WndRow, FALSE);
  526.     }
  527.     /* ----- put the char in the buffer ----- */
  528.     *currchar = c;
  529.     wnd->TextChanged = TRUE;
  530.     if (c == '\n')    {
  531.         wnd->wleft = 0;
  532.         BuildTextPointers(wnd);
  533.         End(wnd);
  534.         Forward(wnd);
  535.         SendMessage(wnd, PAINT, 0, 0);
  536.         return;
  537.     }
  538.     /* ---------- test end of window --------- */
  539.     if (WndCol == ClientWidth(wnd)-1)    {
  540.         int dif;
  541.         char *cp = currchar;
  542.         while (*cp != ' ' && cp != TextLine(wnd, wnd->CurrLine))
  543.             --cp;
  544.         if (!isMultiLine(wnd) || cp == TextLine(wnd, wnd->CurrLine) ||
  545.                 !wnd->WordWrapMode)
  546.             SendMessage(wnd, HORIZSCROLL, TRUE, 0);
  547.         else    {
  548.             dif = 0;
  549.             if (c != ' ')    {
  550.                 dif = (int) (currchar - cp);
  551.                 wnd->CurrCol -= dif;
  552.                 SendMessage(wnd, KEYBOARD, DEL, 0);
  553.                 --dif;
  554.             }
  555.             SendMessage(wnd, KEYBOARD, '\r', 0);
  556.             currchar = CurrChar;
  557.             wnd->CurrCol = dif;
  558.             if (c == ' ')
  559.                 return;
  560.         }
  561.     }
  562.     /* ------ display the character ------ */
  563.     SetStandardColor(wnd);
  564.     PutWindowChar(wnd, c, WndCol, wnd->WndRow);
  565.     /* ----- advance the pointers ------ */
  566.     wnd->CurrCol++;
  567. }
  568.  
  569. static int DoKeyStroke(WINDOW wnd, int c, PARAM p2)
  570. {
  571.     switch (c)    {
  572.         case HOME:
  573.         case END:
  574.         case PGUP:
  575.         case PGDN:
  576.         case CTRL_PGUP:
  577.         case CTRL_PGDN:
  578.         case FWD:
  579.         case BS:
  580.         case CTRL_FWD:
  581.         case CTRL_BS:
  582.         case CTRL_HOME:
  583.         case CTRL_END:
  584.         case RUBOUT:
  585.             if (MovementKey(wnd, c))
  586.                 break;
  587.         case DEL:
  588.             if (DelKey(wnd))
  589.                 return TRUE;
  590.             break;
  591.         case CTRL_FIVE:    /* same as Shift+Tab */
  592.             if (!((int)p2 & (LEFTSHIFT | RIGHTSHIFT)))
  593.                 break;
  594.         case UP:
  595.         case DN:
  596.             if (!isMultiLine(wnd))
  597.                 PostMessage(GetParent(wnd), KEYBOARD, c, p2);
  598.             break;
  599.         case '\t':
  600.             if (TabKey(wnd, p2))
  601.                 return TRUE;
  602.             break;
  603.         case '\r':
  604.             if (!isMultiLine(wnd))    {
  605.                 PostMessage(GetParent(wnd), KEYBOARD, c, p2);
  606.                 break;
  607.             }
  608.             c = '\n';
  609.         default:
  610.             KeyTyped(wnd, c);
  611.             break;
  612.     }
  613.     return FALSE;
  614. }
  615.  
  616. static int KeyboardMsg(WINDOW wnd, PARAM p1, PARAM p2)
  617. {
  618.     int c;
  619.  
  620.     /* --- alt keys get processed by lower classes --- */
  621.     if ((int)p2 & ALTKEY)
  622.         return FALSE;
  623.     c = (int) p1;
  624.     switch (c)    {
  625.         /* --- these keys get processed by lower classes --- */
  626.         case ESC:
  627.         case F1:
  628.         case F2:
  629.         case F3:
  630.         case F4:
  631.         case F5:
  632.         case F6:
  633.         case F7:
  634.         case F8:
  635.         case F9:
  636.         case F10:
  637.         case INS:
  638.         case SHIFT_INS:
  639.         case SHIFT_DEL:
  640.             return FALSE;
  641.         /* --- these keys get processed here --- */
  642.         case CTRL_FWD:
  643.         case CTRL_BS:
  644.         case CTRL_HOME:
  645.         case CTRL_END:
  646.         case CTRL_PGUP:
  647.         case CTRL_PGDN:
  648.             break;
  649.         default:
  650.             /* --- other ctrl keys get processed by lower classes --- */
  651.             if ((int)p2 & CTRLKEY)
  652.                 return FALSE;
  653.             /* --- all other keys get processed here --- */
  654.             break;
  655.     }
  656.     DoMultiLines(wnd, c, p2);
  657.     DoScrolling(wnd, c, p2);
  658.     if (KeyBoardMarking)    {
  659.         int kx, ky;
  660.         SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  661.         SendMessage(NULL, CURRENT_KEYBOARD_CURSOR,
  662.             (PARAM) &kx, (PARAM) &ky);
  663.         SendMessage(wnd, MOUSE_MOVED, kx, ky);
  664.         return TRUE;
  665.     }
  666.     if (!TestAttribute(wnd, READONLY))
  667.         if (DoKeyStroke(wnd, c, p2))
  668.             return TRUE;
  669.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  670.     return TRUE;
  671. }
  672.  
  673. static void DeleteTextCmd(WINDOW wnd)
  674. {
  675.     char *bbl, *bel;
  676.     int len;
  677.  
  678.     if (TextBlockMarked(wnd))    {
  679.         bbl = TextLine(wnd, wnd->BlkBegLine) + wnd->BlkBegCol;
  680.         bel = TextLine(wnd, wnd->BlkEndLine) + wnd->BlkEndCol;
  681.         len = (int) (bel - bbl);
  682.     }
  683.     SaveDeletedText(wnd, bbl, len);
  684.     wnd->TextChanged = TRUE;
  685.     strcpy(bbl, bel);
  686.     wnd->CurrLine = TextLineNumber(wnd, bbl - wnd->BlkBegCol);
  687.     wnd->CurrCol = wnd->BlkBegCol;
  688.     wnd->WndRow = wnd->BlkBegLine - wnd->wtop;
  689.     if (wnd->WndRow < 0)    {
  690.         wnd->wtop = wnd->BlkBegLine;
  691.         wnd->WndRow = 0;
  692.     }
  693.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  694.     ClearTextBlock(wnd);
  695.     BuildTextPointers(wnd);
  696. }
  697.  
  698. static void ClearCmd(WINDOW wnd)
  699. {
  700.     char *bbl, *bel;
  701.     int len;
  702.  
  703.     if (TextBlockMarked(wnd))    {
  704.         bbl = TextLine(wnd, wnd->BlkBegLine) + wnd->BlkBegCol;
  705.         bel = TextLine(wnd, wnd->BlkEndLine) + wnd->BlkEndCol;
  706.         len = (int) (bel - bbl);
  707.     }
  708.     SaveDeletedText(wnd, bbl, len);
  709.     wnd->CurrLine = TextLineNumber(wnd, bbl);
  710.     wnd->CurrCol = wnd->BlkBegCol;
  711.     wnd->WndRow = wnd->BlkBegLine - wnd->wtop;
  712.     if (wnd->WndRow < 0)    {
  713.         wnd->WndRow = 0;
  714.         wnd->wtop = wnd->BlkBegLine;
  715.     }
  716.     while (bbl < bel)    {
  717.         char *cp = strchr(bbl, '\n');
  718.         if (cp > bel)
  719.             cp = bel;
  720.         strcpy(bbl, cp);
  721.         bel -= (int) (cp - bbl);
  722.         bbl++;
  723.     }
  724.     ClearTextBlock(wnd);
  725.     BuildTextPointers(wnd);
  726.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  727.     SendMessage(wnd, PAINT, 0, 0);
  728.     wnd->TextChanged = TRUE;
  729. }
  730.  
  731. static void UndoCmd(WINDOW wnd)
  732. {
  733.     if (wnd->DeletedText != NULL)    {
  734.         PasteText(wnd, wnd->DeletedText, wnd->DeletedLength);
  735.         free(wnd->DeletedText);
  736.         wnd->DeletedText = NULL;
  737.         wnd->DeletedLength = 0;
  738.         SendMessage(wnd, PAINT, 0, 0);
  739.     }
  740. }
  741.  
  742. static void ParagraphCmd(WINDOW wnd)
  743. {
  744.     char *bl;
  745.     int bc, ec;
  746.     int fl, el;
  747.     int Blocked;
  748.     char *bbl, *bel, *bb;
  749.  
  750.     el = wnd->BlkEndLine;
  751.     ec = wnd->BlkEndCol;
  752.     if (!TextBlockMarked(wnd))    {
  753.         Blocked = FALSE;
  754.         /* ---- forming paragraph from cursor position --- */
  755.         fl = wnd->wtop + wnd->WndRow;
  756.         bl = TextLine(wnd, wnd->CurrLine);
  757.         bc = wnd->CurrCol;
  758.         Home(wnd);
  759.         bbl = bel = bl;
  760.         if (bc >= ClientWidth(wnd))
  761.             bc = 0;
  762.         /* ---- locate the end of the paragraph ---- */
  763.         while (*bel)    {
  764.             int blank = TRUE;
  765.             char *bll = bel;
  766.             /* --- blank line marks end of paragraph --- */
  767.             while (*bel && *bel != '\n')    {
  768.                 if (*bel != ' ')
  769.                     blank = FALSE;
  770.                 bel++;
  771.             }
  772.             if (blank)    {
  773.                 bel = bll;
  774.                 break;
  775.             }
  776.             if (*bel)
  777.                 bel++;
  778.         }
  779.         if (bel == bbl)    {
  780.             SendMessage(wnd, KEYBOARD, DN, 0);
  781.             return;
  782.         }
  783.         if (*bel == '\0')
  784.             --bel;
  785.         if (*bel == '\n')
  786.             --bel;
  787.     }
  788.     else    {
  789.         bbl = TextLine(wnd, wnd->BlkBegLine) + wnd->BlkBegCol;
  790.         bel = TextLine(wnd, wnd->BlkEndLine) + wnd->BlkEndCol;
  791.  
  792.         Blocked = TRUE;
  793.         /* ---- forming paragraph from marked block --- */
  794.         fl = wnd->BlkBegLine;
  795.         bc = wnd->CurrCol = wnd->BlkBegCol;
  796.         wnd->CurrLine = fl;
  797.         if (fl < wnd->wtop)
  798.             wnd->wtop = fl;
  799.         wnd->WndRow = fl - wnd->wtop;
  800.         SendMessage(wnd, KEYBOARD, '\r', 0);
  801.         el++, fl++;
  802.         if (bc != 0)    {
  803.             SendMessage(wnd, KEYBOARD, '\r', 0);
  804.             el++, fl ++;
  805.         }
  806.         bc = 0;
  807.         bl = TextLine(wnd, fl);
  808.         wnd->CurrLine = fl;
  809.         bbl = bl + bc;
  810.         bel = TextLine(wnd, el) + ec;
  811.     }
  812.  
  813.     /* --- change all newlines in block to spaces --- */
  814.     while (CurrChar < bel)    {
  815.         if (*CurrChar == '\n')    {
  816.             *CurrChar = ' ';
  817.             wnd->CurrLine++;
  818.             wnd->CurrCol = 0;
  819.         }
  820.         else
  821.             wnd->CurrCol++;
  822.     }
  823.  
  824.     /* ---- insert newlines at new margin boundaries ---- */
  825.     bb = bbl;
  826.     while (bbl < bel)    {
  827.         bbl++;
  828.         if ((int)(bbl - bb) == ClientWidth(wnd)-1)    {
  829.             while (*bbl != ' ' && bbl > bb)
  830.                 --bbl;
  831.             if (*bbl != ' ')    {
  832.                 bbl = strchr(bbl, ' ');
  833.                 if (bbl == NULL || bbl >= bel)
  834.                     break;
  835.             }
  836.             *bbl = '\n';
  837.             bb = bbl+1;
  838.         }
  839.     }
  840.     ec = (int)(bel - bb);
  841.     BuildTextPointers(wnd);
  842.  
  843.     if (Blocked)    {
  844.         /* ---- position cursor at end of new paragraph ---- */
  845.         if (el < wnd->wtop ||
  846.                 wnd->wtop + ClientHeight(wnd) < el)
  847.             wnd->wtop = el-ClientHeight(wnd);
  848.         if (wnd->wtop < 0)
  849.             wnd->wtop = 0;
  850.         wnd->WndRow = el - wnd->wtop;
  851.         wnd->CurrLine = el;
  852.         wnd->CurrCol = ec;
  853.         SendMessage(wnd, KEYBOARD, '\r', 0);
  854.         SendMessage(wnd, KEYBOARD, '\r', 0);
  855.     }
  856.     else    {
  857.         /* --- put cursor back at beginning --- */
  858.         wnd->CurrLine = TextLineNumber(wnd, bl);
  859.         wnd->CurrCol = bc;
  860.         if (fl < wnd->wtop)
  861.             wnd->wtop = fl;
  862.         wnd->WndRow = fl - wnd->wtop;
  863.     }
  864.     SendMessage(wnd, PAINT, 0, 0);
  865.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  866.     wnd->TextChanged = TRUE;
  867.     BuildTextPointers(wnd);
  868. }
  869.  
  870. static int CommandMsg(WINDOW wnd, PARAM p1)
  871. {
  872.     switch ((int)p1)    {
  873.         case ID_DELETETEXT:
  874.             DeleteTextCmd(wnd);
  875.             return TRUE;
  876.         case ID_CLEAR:
  877.             ClearCmd(wnd);
  878.             return TRUE;
  879.         case ID_UNDO:
  880.             UndoCmd(wnd);
  881.             return TRUE;
  882.         case ID_PARAGRAPH:
  883.             ParagraphCmd(wnd);
  884.             return TRUE;
  885.         default:
  886.             break;
  887.     }
  888.     return FALSE;
  889. }
  890.  
  891. int EditBoxProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2)
  892. {
  893.     int rtn;
  894.     RECT rc;
  895.  
  896.     rc = ClientRect(wnd);
  897.     switch (msg)    {
  898.         case CREATE_WINDOW:
  899.             return CreateWindowMsg(wnd);
  900.         case ADDTEXT:
  901.             return AddTextMsg(wnd, p1, p2);
  902.         case SETTEXT:
  903.             rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2);
  904.             wnd->CurrLine = 0;
  905.             return rtn;
  906.         case CLEARTEXT:
  907.             ResetEditBox(wnd);
  908.             ClearTextPointers(wnd);
  909.             break;
  910.         case KEYBOARD_CURSOR:
  911.             return KeyboardCursorMsg(wnd, p1, p2);
  912.         case EB_GETTEXT:
  913.             GetTextMsg(wnd, p1, p2);
  914.             return TRUE;
  915.         case EB_PUTTEXT:
  916.             SendMessage(wnd, CLEARTEXT, 0, 0);
  917.             SendMessage(wnd, ADDTEXT, p1, p2);
  918.             return TRUE;
  919.         case SETFOCUS:
  920.             return SetFocusMsg(wnd, p1);
  921.         case SHIFT_CHANGED:
  922.             ShiftChangedMsg(wnd, p1);
  923.             break;
  924.         case DOUBLE_CLICK:
  925.             if (KeyBoardMarking)
  926.                 return TRUE;
  927.             break;
  928.         case LEFT_BUTTON:
  929.             if (KeyBoardMarking || TextMarking)
  930.                 return TRUE;
  931.             if (WindowMoving || WindowSizing)
  932.                 break;
  933.             if (!InsideRect(p1, p2, rc))
  934.                 break;
  935.             LeftButtonMsg(wnd, p1, p2);
  936.             return TRUE;
  937.         case MOUSE_MOVED:
  938.             if (MouseMovedMsg(wnd, p1, p2))
  939.                 return TRUE;
  940.             break;
  941.         case BUTTON_RELEASED:
  942.             if (ButtonReleasedMsg(wnd))
  943.                 return TRUE;
  944.             break;
  945.         case PAINT:
  946.             rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2);
  947.             if (isVisible(wnd))
  948.                 SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  949.             return rtn;
  950.         case SCROLL:
  951.             return ScrollMsg(wnd, p1, p2);
  952.         case HORIZSCROLL:
  953.             return HorizScrollMsg(wnd, p1);
  954.  
  955.         case MOVE:
  956.             rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2);
  957.             SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  958.             return rtn;
  959.         case SIZE:
  960.             return SizeMsg(wnd, p1, p2);
  961.         case SCROLLPAGE:
  962.             return ScrollPageMsg(wnd, p1);
  963.         case HORIZPAGE:
  964.             return HorizPageMsg(wnd, p1);
  965.         case KEYBOARD:
  966.             if (WindowMoving || WindowSizing)
  967.                 break;
  968.             if (KeyboardMsg(wnd, p1, p2))
  969.                 return TRUE;
  970.             break;
  971.         case COMMAND:
  972.             if (CommandMsg(wnd, p1))
  973.                 return TRUE;
  974.             break;
  975.         case CLOSE_WINDOW:
  976.             SendMessage(NULL, HIDE_CURSOR, 0, 0);
  977.             if (wnd->DeletedText != NULL)
  978.                 free(wnd->DeletedText);
  979.             break;
  980.         default:
  981.             break;
  982.     }
  983.     return BaseWndProc(EDITBOX, wnd, msg, p1, p2);
  984. }
  985.  
  986. static void SaveDeletedText(WINDOW wnd, char *bbl, int len)
  987. {
  988.     wnd->DeletedLength = len;
  989.     if ((wnd->DeletedText = realloc(wnd->DeletedText, len)) != NULL)
  990.         memmove(wnd->DeletedText, bbl, len);
  991. }
  992.  
  993. static void Forward(WINDOW wnd)
  994. {
  995.     char *cc = CurrChar+1;
  996.     if (*cc == '\0')
  997.         return;
  998.     if (*CurrChar == '\n')    {
  999.         Home(wnd);
  1000.         Downward(wnd);
  1001.     }
  1002.     else    {
  1003.         wnd->CurrCol++;
  1004.         if (WndCol == ClientWidth(wnd))
  1005.             SendMessage(wnd, HORIZSCROLL, TRUE, 0);
  1006.     }
  1007. }
  1008.  
  1009. static void StickEnd(WINDOW wnd)
  1010. {
  1011.     char *cp = TextLine(wnd, wnd->CurrLine);
  1012.     char *cp1 = strchr(cp, '\n');
  1013.     int len = 0;
  1014.  
  1015.     if (cp1 != NULL)
  1016.         len = (int) (cp1 - cp);
  1017.     wnd->CurrCol = min(len, wnd->CurrCol);
  1018.     if (wnd->wleft > wnd->CurrCol)    {
  1019.         wnd->wleft = max(0, wnd->CurrCol - 4);
  1020.         SendMessage(wnd, PAINT, 0, 0);
  1021.     }
  1022.     else if (wnd->CurrCol-wnd->wleft >= ClientWidth(wnd))    {
  1023.         wnd->wleft = wnd->CurrCol - (ClientWidth(wnd)-1);
  1024.         SendMessage(wnd, PAINT, 0, 0);
  1025.     }
  1026. }
  1027.  
  1028. static void Downward(WINDOW wnd)
  1029. {
  1030.     if (isMultiLine(wnd) && wnd->WndRow+wnd->wtop+1 < wnd->wlines)    {
  1031.         DownLine(wnd);
  1032.         if (wnd->WndRow == ClientHeight(wnd)-1)
  1033.             SendMessage(wnd, SCROLL, TRUE, 0);
  1034.         wnd->WndRow++;
  1035.         StickEnd(wnd);
  1036.     }
  1037. }
  1038.  
  1039. static void DownLine(WINDOW wnd)
  1040. {
  1041.     wnd->CurrLine++;
  1042. }
  1043.  
  1044. static void UpLine(WINDOW wnd)
  1045. {
  1046.     if (wnd->CurrLine > 0)
  1047.         --wnd->CurrLine;
  1048. }
  1049.  
  1050. static void Upward(WINDOW wnd)
  1051. {
  1052.     if (isMultiLine(wnd) && wnd->CurrLine != 0)    {
  1053.         UpLine(wnd);
  1054.         if (wnd->WndRow == 0)
  1055.             SendMessage(wnd, SCROLL, FALSE, 0);
  1056.         --wnd->WndRow;
  1057.         StickEnd(wnd);
  1058.     }
  1059. }
  1060.  
  1061. static void Backward(WINDOW wnd)
  1062. {
  1063.     if (wnd->CurrCol)    {
  1064.         if (wnd->CurrCol-- <= wnd->wleft)
  1065.             if (wnd->wleft != 0)
  1066.                 SendMessage(wnd, HORIZSCROLL, FALSE, 0);
  1067.     }
  1068.     else if (isMultiLine(wnd) && wnd->CurrLine != 0)    {
  1069.         Upward(wnd);
  1070.         End(wnd);
  1071.     }
  1072. }
  1073.  
  1074. static void End(WINDOW wnd)
  1075. {
  1076.     while (*CurrChar && *CurrChar != '\n')
  1077.         ++wnd->CurrCol;
  1078.     if (WndCol >= ClientWidth(wnd))    {
  1079.         wnd->wleft = wnd->CurrCol - (ClientWidth(wnd)-1);
  1080.         SendMessage(wnd, PAINT, 0, 0);
  1081.     }
  1082. }
  1083.  
  1084. static void Home(WINDOW wnd)
  1085. {
  1086.     wnd->CurrCol = 0;
  1087.     if (wnd->wleft != 0)    {
  1088.         wnd->wleft = 0;
  1089.         SendMessage(wnd, PAINT, 0, 0);
  1090.     }
  1091. }
  1092.  
  1093. #define isWhite(c)     ((c) == ' ' || (c) == '\n')
  1094.  
  1095. static void NextWord(WINDOW wnd)
  1096. {
  1097.     int savetop = wnd->wtop;
  1098.     int saveleft = wnd->wleft;
  1099.     ClearVisible(wnd);
  1100.     while (!isWhite(*CurrChar))    {
  1101.         char *cc = CurrChar+1;
  1102.         if (*cc == '\0')
  1103.             break;
  1104.         Forward(wnd);
  1105.     }
  1106.     while (isWhite(*CurrChar))    {
  1107.         char *cc = CurrChar+1;
  1108.         if (*cc == '\0')
  1109.             break;
  1110.         Forward(wnd);
  1111.     }
  1112.     SetVisible(wnd);
  1113.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  1114.     if (wnd->wtop != savetop || wnd->wleft != saveleft)
  1115.         SendMessage(wnd, PAINT, 0, 0);
  1116. }
  1117.  
  1118. static void PrevWord(WINDOW wnd)
  1119. {
  1120.     int savetop = wnd->wtop;
  1121.     int saveleft = wnd->wleft;
  1122.     ClearVisible(wnd);
  1123.     Backward(wnd);
  1124.     while (isWhite(*CurrChar))    {
  1125.         if (wnd->CurrLine == 0 && wnd->CurrCol == 0)
  1126.             break;
  1127.         Backward(wnd);
  1128.     }
  1129.     while (!isWhite(*CurrChar))    {
  1130.         if (wnd->CurrLine == 0 && wnd->CurrCol == 0)
  1131.             break;
  1132.         Backward(wnd);
  1133.     }
  1134.     if (isWhite(*CurrChar))
  1135.         Forward(wnd);
  1136.     SetVisible(wnd);
  1137.     if (wnd->wleft != saveleft)
  1138.         if (wnd->CurrCol >= saveleft)
  1139.             if (wnd->CurrCol - saveleft < ClientWidth(wnd))
  1140.                 wnd->wleft = saveleft;
  1141.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  1142.     if (wnd->wtop != savetop || wnd->wleft != saveleft)
  1143.         SendMessage(wnd, PAINT, 0, 0);
  1144. }
  1145.  
  1146. static void ResetEditBox(WINDOW wnd)
  1147. {
  1148.     *wnd->text = '\0';
  1149.     wnd->wlines = 0;
  1150.     wnd->CurrLine = 0;
  1151.     wnd->CurrCol = 0;
  1152.     wnd->WndRow = 0;
  1153.     wnd->TextChanged = FALSE;
  1154.     wnd->wleft = 0;
  1155.     wnd->textwidth = 0;
  1156. }
  1157.  
  1158. static void AddTextPointers(WINDOW wnd, int lineno, int ct)
  1159. {
  1160.     while (lineno < wnd->wlines)
  1161.         *((wnd->TextPointers) + lineno++) += ct;
  1162. }
  1163.  
  1164.